import { useLayoutEffect, useState } from 'react'
import { Router, BrowserRouterProps } from 'react-router-dom'

// import type 表示显示指定导入的内容为 TS 类型
import type { BrowserHistory } from 'history'

type Props = BrowserRouterProps & {
  history: BrowserHistory
}

// 参考：
// https://github.com/remix-run/react-router/blob/main/packages/react-router-dom/index.tsx#L133-L160
// 使用：
/*
  history 就是一个专门用来管理 浏览器历史记录 的 JS 库，可以在任何运行 JS 的地方来运行
  这个包里面提供了 history.push() / history.repleace() 等路由跳转的方法

  react-router-dom 这个包，内部是使用 history 包，来实现路由跳转的。 它内部封装了 hisotry，
  将其封装成了 React 组件，这样，我们就可以按照 React 组件的方式，来使用 路由 了

  // --

  不管是使用 react 路由默认提供的 BrowserRouter 还是现在我们要自己创建的 CustomRouter
  都必须要使用它包裹整个项目，这样，整个项目的任意位置才能实现路由跳转

  使用 BrowserRouter 和 CustomRouter 的区别：
  
  如果使用 BrowserRouter 是无法获取到 history 对象的，所以，也就无法直接在组件外部来做路由跳转
  <BrowserRouter>
    <Routes>
      <Route path="/" element={<Navigate to="/home" />} />
    </Routes>
  </BrowserRouter>

  如果使用 CustomRouter 就可以手动为它指定 history 对象，指定后，不管是 Router 组件内部
  还是组件外部，都可以拿到同一个 customHistory 。 这样处理后，在项目中的任意位置都可以进行路由跳转了
  <CustomRouter history={customHistory}>
    <Routes>
      <Route path="/" element={<Navigate to="/home" />} />
    </Routes>
  </CustomRouter>

  // --
  BrowserRouter = Router组件 + 内部定制好的history（ 根 brower 相关， createBrowserHistory 函数创建的 history 对象 ）
  HashRouter = Router组件 + 内部定制好的history （ 根 hash 相关， createHashHistory 函数创建的 history 对象 ）

  CustomRouter = Router组件 + 我们自定义的history （ createBrowserHistory 函数创建的 history 对象 ）
*/

const CustomRouter = ({ history, ...restProps }: Props) => {
  const [state, setState] = useState({
    // 路由跳转类型，比如， push / replace
    action: history.action,
    location: history.location,
  })

  // useEffect vs. useLayoutEffect
  // https://codesandbox.io/s/uselayouteffect-vs-useeffect-1-v4f4yh?file=/src/App.js
  useLayoutEffect(() => history.listen(setState), [history])

  return (
    <Router
      {...restProps}
      location={state.location}
      navigationType={state.action}
      navigator={history}
    />
  )
}

export default CustomRouter
